package com.xxcxcxcx.jobsystem.packet;

import com.xxcxcxcx.jobsystem.common.JobsClass;
import com.xxcxcxcx.jobsystem.common.capability.JobCapabilityProvider;
import net.minecraft.client.Minecraft;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.protocol.Packet;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.fml.DistExecutor;
import net.minecraftforge.fml.LogicalSide;
import net.minecraftforge.network.NetworkEvent;

import javax.annotation.Nullable;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.function.Supplier;

public class ServerLevelPacket {
    protected final Map<String, Integer> level;
    protected final Map<String, Double> experience;
    protected final Map<String, Double> coefficient;
    protected final UUID entityId;

    public ServerLevelPacket(Player player, HashMap<String, Integer> l, Map<String, Double> e, Map<String, Double> c) {
        entityId = player.getUUID();
        level = l;
        experience = e;
        coefficient = c;
    }

    public ServerLevelPacket(FriendlyByteBuf friendlyByteBuf) {
        entityId = friendlyByteBuf.readUUID();
        level = new HashMap<>();
        experience = new HashMap<>();
        coefficient = new HashMap<>();
        for(int i = 0; i < JobsClass.Jobs.length; i++) {
            level.put(JobsClass.Jobs[i], friendlyByteBuf.readInt());
            experience.put(JobsClass.Jobs[i], friendlyByteBuf.readDouble());
            coefficient.put(JobsClass.Jobs[i], friendlyByteBuf.readDouble());
        }
    }

    public void write(FriendlyByteBuf buf) {
        buf.writeUUID(entityId);
        for(int i = 0; i < JobsClass.Jobs.length; i++) {
            buf.writeInt(level.get(JobsClass.Jobs[i]));
            buf.writeDouble(experience.get(JobsClass.Jobs[i]));
            buf.writeDouble(coefficient.get(JobsClass.Jobs[i]));
        }
    }

    public String toString() {
        return "Entity_" + super.toString();
    }

    public Map<String, Integer> getLevel() {
        return level;
    }

    public Map<String, Double> getExp() {
        return experience;
    }

    public Map<String, Double> getCoe() {
        return coefficient;
    }

    @Nullable
    public Player getEntity(Level level) {
        return level.getPlayerByUUID(this.entityId);
    }

    public static class LevelPacketHandler {
        @OnlyIn(Dist.CLIENT)
        public static void handlePacket(ServerLevelPacket msg, Supplier<NetworkEvent.Context> ctx) {
            Player entity = Minecraft.getInstance().player;
            if(entity != null) {
                JobCapabilityProvider.getPlayerData(entity).ifPresent(playerSaveData -> {
                    for(int i = 0; i < JobsClass.Jobs.length; i++) {
                        playerSaveData.setLevel(JobsClass.Jobs[i], msg.getLevel().get(JobsClass.Jobs[i]));
                        playerSaveData.setExperience(JobsClass.Jobs[i], msg.getExp().get(JobsClass.Jobs[i]));
                        playerSaveData.setCoefficient(JobsClass.Jobs[i], msg.getCoe().get(JobsClass.Jobs[i]));
                    }
                });
            }
        }

        public static void handle(ServerLevelPacket msg, Supplier<NetworkEvent.Context> ctx) {
            ctx.get().enqueueWork(() ->
                    // Make sure it's only executed on the physical client
                    DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> handlePacket(msg, ctx))
            );
            ctx.get().setPacketHandled(true);
        }
    }
}